

package service

import (
	"context"
	"fmt"
	"log"
	"math"
	"strconv"
	"sync"
	"time"

	"github.com/adshao/go-binance/v2"
	"github.com/gorilla/websocket"
)

// DogeUSDTForecastService DOGE/USDT单边上涨评分系统（基于WebSocket实时监控）
// 注意：这是实验性功能，不应用于实际交易机器人
type DogeUSDTForecastService struct {
	client       *binance.Client
	symbol       string
	klineData    []*binance.Kline // 存储K线数据
	rsiBuf       []float64        // RSI计算缓冲区
	volumeAvg    float64          // 成交量平均值
	lastUpdate   time.Time        // 最后更新时间
	
	// WebSocket相关字段
	wsConn       *websocket.Conn  // WebSocket连接
	wsKlineConn  *websocket.Conn  // K线WebSocket连接
	wsTickerConn *websocket.Conn  // 价格WebSocket连接
	isRunning    bool             // 服务运行状态
	stopChan     chan struct{}    // 停止信号通道
	dataMutex    sync.RWMutex     // 数据读写锁
	
	// 实时数据
	currentPrice float64          // 实时价格
	currentVolume float64         // 实时成交量
	lastKline    *binance.Kline   // 最新K线
	
	// 事件回调
	onPriceUpdate    func(price float64)        // 价格更新回调
	onScoreUpdate    func(score *ForecastScore) // 评分更新回调
	onKlineUpdate    func(kline *binance.Kline) // K线更新回调
}

// ForecastScore 评分结果
type ForecastScore struct {
	TotalScore    float64            `json:"total_score"`    // 总评分
	MaxScore      float64            `json:"max_score"`      // 最大可能评分
	ScorePercent  float64            `json:"score_percent"`  // 评分百分比
	Indicators    map[string]float64 `json:"indicators"`     // 各指标得分
	CurrentPrice  float64            `json:"current_price"`  // 当前价格
	Timestamp     time.Time          `json:"timestamp"`      // 评分时间
	Recommendation string            `json:"recommendation"` // 推荐操作
}

// NewDogeUSDTForecastService 创建DOGE/USDT预测服务
func NewDogeUSDTForecastService(client *binance.Client) *DogeUSDTForecastService {
	return &DogeUSDTForecastService{
		client:   client,
		symbol:   "DOGEUSDT",
		rsiBuf:   make([]float64, 0, 100),
		stopChan: make(chan struct{}),
	}
}

// SetPriceUpdateCallback 设置价格更新回调
func (d *DogeUSDTForecastService) SetPriceUpdateCallback(callback func(price float64)) {
	d.onPriceUpdate = callback
}

// SetScoreUpdateCallback 设置评分更新回调
func (d *DogeUSDTForecastService) SetScoreUpdateCallback(callback func(score *ForecastScore)) {
	d.onScoreUpdate = callback
}

// SetKlineUpdateCallback 设置K线更新回调
func (d *DogeUSDTForecastService) SetKlineUpdateCallback(callback func(kline *binance.Kline)) {
	d.onKlineUpdate = callback
}

// InitializeData 初始化历史数据
func (d *DogeUSDTForecastService) InitializeData() error {
	// 获取最近200根K线数据用于计算技术指标，确保有足够的数据
	klines, err := d.client.NewKlinesService().
		Symbol(d.symbol).
		Interval("1d"). // 日线数据
		Limit(200).     // 增加到200根，确保有足够数据
		Do(context.Background())

	if err != nil {
		return fmt.Errorf("获取K线数据失败: %v", err)
	}

	// 验证数据量是否足够
	if len(klines) < 50 {
		return fmt.Errorf("获取的K线数据不足，仅获取到%d根，需要至少50根", len(klines))
	}

	d.dataMutex.Lock()
	d.klineData = klines
	d.calculateVolumeAverage()
	d.lastUpdate = time.Now()
	d.dataMutex.Unlock()

	log.Printf("DOGE/USDT预测服务初始化完成，加载了%d根K线数据", len(klines))
	return nil
}

// StartRealTimeMonitoring 启动实时监控
func (d *DogeUSDTForecastService) StartRealTimeMonitoring() error {
	if d.isRunning {
		return fmt.Errorf("实时监控已在运行中")
	}

	// 启动价格监控WebSocket
	if err := d.startPriceWebSocket(); err != nil {
		return fmt.Errorf("启动价格WebSocket失败: %v", err)
	}

	// 启动K线监控WebSocket
	if err := d.startKlineWebSocket(); err != nil {
		return fmt.Errorf("启动K线WebSocket失败: %v", err)
	}

	d.isRunning = true
	log.Printf("DOGE/USDT实时监控已启动")
	return nil
}

// StopRealTimeMonitoring 停止实时监控
func (d *DogeUSDTForecastService) StopRealTimeMonitoring() {
	if !d.isRunning {
		return
	}

	close(d.stopChan)
	d.isRunning = false

	// 关闭WebSocket连接
	if d.wsTickerConn != nil {
		d.wsTickerConn.Close()
	}
	if d.wsKlineConn != nil {
		d.wsKlineConn.Close()
	}

	log.Printf("DOGE/USDT实时监控已停止")
}

// IsRunning 检查服务是否正在运行
func (d *DogeUSDTForecastService) IsRunning() bool {
	return d.isRunning
}

// startPriceWebSocket 启动价格监控WebSocket
func (d *DogeUSDTForecastService) startPriceWebSocket() error {
	wsTickerHandler := func(event *binance.WsBookTickerEvent) {
		if event.Symbol == d.symbol {
			price, _ := strconv.ParseFloat(event.BestBidPrice, 64)
			d.dataMutex.Lock()
			d.currentPrice = price
			d.dataMutex.Unlock()

			// 触发价格更新回调
			if d.onPriceUpdate != nil {
				d.onPriceUpdate(price)
			}

			// 价格变化时重新计算评分
			go d.calculateAndNotifyScore()
		}
	}

	errorHandler := func(err error) {
		log.Printf("价格WebSocket错误: %v", err)
	}

	doneC, stopC, err := binance.WsBookTickerServe(d.symbol, wsTickerHandler, errorHandler)
	if err != nil {
		return err
	}

	// 启动goroutine监听停止信号
	go func() {
		select {
		case <-d.stopChan:
			close(stopC)
		case <-doneC:
			log.Printf("价格WebSocket连接已关闭")
		}
	}()

	return nil
}

// startKlineWebSocket 启动K线监控WebSocket
func (d *DogeUSDTForecastService) startKlineWebSocket() error {
	wsKlineHandler := func(event *binance.WsKlineEvent) {
		if event.Symbol == d.symbol && event.Kline.IsFinal {
			// 转换为binance.Kline格式
			kline := &binance.Kline{
				OpenTime:                 event.Kline.StartTime,
				Open:                     event.Kline.Open,
				High:                     event.Kline.High,
				Low:                      event.Kline.Low,
				Close:                    event.Kline.Close,
				Volume:                   event.Kline.Volume,
				CloseTime:                event.Kline.EndTime,
				QuoteAssetVolume:         event.Kline.QuoteVolume,
				TradeNum:                 event.Kline.TradeNum,
				TakerBuyBaseAssetVolume:  event.Kline.ActiveBuyVolume,
				TakerBuyQuoteAssetVolume: event.Kline.ActiveBuyQuoteVolume,
			}

			d.dataMutex.Lock()
			// 更新K线数据
			d.updateKlineData(kline)
			d.lastKline = kline
			volume, _ := strconv.ParseFloat(kline.Volume, 64)
			d.currentVolume = volume
			d.lastUpdate = time.Now()
			d.dataMutex.Unlock()

			// 触发K线更新回调
			if d.onKlineUpdate != nil {
				d.onKlineUpdate(kline)
			}

			// K线更新时重新计算评分
			go d.calculateAndNotifyScore()
		}
	}

	errorHandler := func(err error) {
		log.Printf("K线WebSocket错误: %v", err)
	}

	doneC, stopC, err := binance.WsKlineServe(d.symbol, "1d", wsKlineHandler, errorHandler)
	if err != nil {
		return err
	}

	// 启动goroutine监听停止信号
	go func() {
		select {
		case <-d.stopChan:
			close(stopC)
		case <-doneC:
			log.Printf("K线WebSocket连接已关闭")
		}
	}()

	return nil
}

// updateKlineData 更新K线数据
func (d *DogeUSDTForecastService) updateKlineData(newKline *binance.Kline) {
	// 检查是否是新的K线还是更新现有K线
	if len(d.klineData) > 0 {
		lastKline := d.klineData[len(d.klineData)-1]
		if lastKline.OpenTime == newKline.OpenTime {
			// 更新现有K线
			d.klineData[len(d.klineData)-1] = newKline
		} else {
			// 添加新K线
			d.klineData = append(d.klineData, newKline)
			// 保持数据量在合理范围内
			if len(d.klineData) > 250 {
				d.klineData = d.klineData[50:] // 保留最近200根
			}
		}
	} else {
		d.klineData = append(d.klineData, newKline)
	}

	// 重新计算成交量平均值
	d.calculateVolumeAverage()
}

// calculateAndNotifyScore 计算并通知评分更新
func (d *DogeUSDTForecastService) calculateAndNotifyScore() {
	score, err := d.CalculateScore()
	if err != nil {
		log.Printf("计算评分失败: %v", err)
		return
	}

	// 触发评分更新回调
	if d.onScoreUpdate != nil {
		d.onScoreUpdate(score)
	}
}

// CalculateScore 计算单边上涨评分
func (d *DogeUSDTForecastService) CalculateScore() (*ForecastScore, error) {
	d.dataMutex.RLock()
	defer d.dataMutex.RUnlock()

	// 检查数据是否准备就绪
	if !d.isDataReady() {
		return nil, fmt.Errorf("数据未准备就绪，当前有%d根K线数据，需要至少50根K线数据进行分析", len(d.klineData))
	}

	score := &ForecastScore{
		Indicators: make(map[string]float64),
		Timestamp:  time.Now(),
		MaxScore:   100.0, // 总分100%
	}

	// 获取当前价格
	currentPrice := d.getCurrentPrice()
	score.CurrentPrice = currentPrice

	// 计算各项技术指标评分
	score.Indicators["MA多头排列"] = d.calculateMABullishAlignment() * 20.0
	score.Indicators["RSI>60"] = d.calculateRSIAbove60() * 15.0
	score.Indicators["RSI连续上升3日"] = d.calculateRSIRising3Days() * 15.0
	score.Indicators["成交量>1.5倍均值"] = d.calculateVolumeAboveAverage() * 15.0
	score.Indicators["当前价格>20MA"] = d.calculatePriceAbove20MA(currentPrice) * 10.0
	score.Indicators["连续3根阳线"] = d.calculateConsecutiveBullCandles() * 5.0
	score.Indicators["突破布林带上轨"] = d.calculateBollingerBreakout(currentPrice) * 10.0
	score.Indicators["连续2日收盘价>上轨"] = d.calculateConsecutiveAboveBollinger() * 10.0

	// 计算总分
	for _, value := range score.Indicators {
		score.TotalScore += value
	}

	score.ScorePercent = score.TotalScore / score.MaxScore * 100

	// 生成推荐
	score.Recommendation = d.generateRecommendation(score.ScorePercent)

	return score, nil
}

// calculateMABullishAlignment 计算MA多头排列 (5MA > 10MA > 20MA > 50MA)
func (d *DogeUSDTForecastService) calculateMABullishAlignment() float64 {
	if len(d.klineData) < 50 {
		return 0
	}

	ma5 := d.calculateMA(5)
	ma10 := d.calculateMA(10)
	ma20 := d.calculateMA(20)
	ma50 := d.calculateMA(50)

	if ma5 > ma10 && ma10 > ma20 && ma20 > ma50 {
		return 1.0 // 完美多头排列
	}
	return 0
}

// calculateRSIAbove60 计算RSI > 60
func (d *DogeUSDTForecastService) calculateRSIAbove60() float64 {
	rsi := d.calculateRSI(14)
	if rsi > 60 {
		return 1.0
	}
	return 0
}

// calculateRSIRising3Days 计算RSI连续上升3日
func (d *DogeUSDTForecastService) calculateRSIRising3Days() float64 {
	if len(d.klineData) < 17 { // 需要14+3天数据
		return 0
	}

	// 计算最近4天的RSI
	rsiValues := make([]float64, 4)
	for i := 0; i < 4; i++ {
		subData := d.klineData[len(d.klineData)-17+i : len(d.klineData)-3+i]
		rsiValues[i] = d.calculateRSIFromData(subData, 14)
	}

	// 检查是否连续3日上升
	for i := 1; i < 4; i++ {
		if rsiValues[i] <= rsiValues[i-1] {
			return 0
		}
	}
	return 1.0
}

// calculateMA 计算移动平均线
func (d *DogeUSDTForecastService) calculateMA(period int) float64 {
	if len(d.klineData) < period {
		return 0
	}

	sum := 0.0
	for i := len(d.klineData) - period; i < len(d.klineData); i++ {
		close, _ := strconv.ParseFloat(d.klineData[i].Close, 64)
		sum += close
	}
	return sum / float64(period)
}

// calculateRSI 计算RSI指标
func (d *DogeUSDTForecastService) calculateRSI(period int) float64 {
	if len(d.klineData) < period+1 {
		return 50 // 默认中性值
	}

	return d.calculateRSIFromData(d.klineData, period)
}

// calculateRSIFromData 从指定数据计算RSI
func (d *DogeUSDTForecastService) calculateRSIFromData(data []*binance.Kline, period int) float64 {
	if len(data) < period+1 {
		return 50
	}

	gains := make([]float64, 0)
	losses := make([]float64, 0)

	// 计算价格变化
	for i := 1; i < len(data); i++ {
		prevClose, _ := strconv.ParseFloat(data[i-1].Close, 64)
		currClose, _ := strconv.ParseFloat(data[i].Close, 64)
		change := currClose - prevClose

		if change > 0 {
			gains = append(gains, change)
			losses = append(losses, 0)
		} else {
			gains = append(gains, 0)
			losses = append(losses, -change)
		}
	}

	if len(gains) < period {
		return 50
	}

	// 计算平均收益和损失
	avgGain := 0.0
	avgLoss := 0.0
	for i := len(gains) - period; i < len(gains); i++ {
		avgGain += gains[i]
		avgLoss += losses[i]
	}
	avgGain /= float64(period)
	avgLoss /= float64(period)

	if avgLoss == 0 {
		return 100
	}

	rs := avgGain / avgLoss
	rsi := 100 - (100 / (1 + rs))
	return rsi
}

// calculateBollingerUpperBand 计算布林带上轨
func (d *DogeUSDTForecastService) calculateBollingerUpperBand(period int, multiplier float64) float64 {
	return d.calculateBollingerUpperBandFromData(d.klineData, period, multiplier)
}

// calculateBollingerUpperBandFromData 从指定数据计算布林带上轨
func (d *DogeUSDTForecastService) calculateBollingerUpperBandFromData(data []*binance.Kline, period int, multiplier float64) float64 {
	if len(data) < period {
		return 0
	}

	// 计算移动平均
	sum := 0.0
	prices := make([]float64, period)
	for i := 0; i < period; i++ {
		close, _ := strconv.ParseFloat(data[len(data)-period+i].Close, 64)
		prices[i] = close
		sum += close
	}
	ma := sum / float64(period)

	// 计算标准差
	variance := 0.0
	for _, price := range prices {
		variance += math.Pow(price-ma, 2)
	}
	stdDev := math.Sqrt(variance / float64(period))

	return ma + (multiplier * stdDev)
}

// calculateVolumeAverage 计算成交量平均值
func (d *DogeUSDTForecastService) calculateVolumeAverage() {
	if len(d.klineData) == 0 {
		d.volumeAvg = 0
		return
	}

	sum := 0.0
	for _, kline := range d.klineData {
		volume, _ := strconv.ParseFloat(kline.Volume, 64)
		sum += volume
	}
	d.volumeAvg = sum / float64(len(d.klineData))
}

// getCurrentPrice 获取当前价格（优先使用实时价格）
func (d *DogeUSDTForecastService) getCurrentPrice() float64 {
	// 如果有实时价格，优先使用实时价格
	if d.currentPrice > 0 {
		return d.currentPrice
	}

	// 否则使用最新K线的收盘价
	if len(d.klineData) == 0 {
		return 0
	}

	lastKline := d.klineData[len(d.klineData)-1]
	price, _ := strconv.ParseFloat(lastKline.Close, 64)
	return price
}

// GetCurrentPrice 获取当前实时价格（线程安全）
func (d *DogeUSDTForecastService) GetCurrentPrice() float64 {
	d.dataMutex.RLock()
	defer d.dataMutex.RUnlock()
	return d.getCurrentPrice()
}

// GetCurrentVolume 获取当前实时成交量（线程安全）
func (d *DogeUSDTForecastService) GetCurrentVolume() float64 {
	d.dataMutex.RLock()
	defer d.dataMutex.RUnlock()
	return d.currentVolume
}

// GetLastKline 获取最新K线（线程安全）
func (d *DogeUSDTForecastService) GetLastKline() *binance.Kline {
	d.dataMutex.RLock()
	defer d.dataMutex.RUnlock()
	return d.lastKline
}

// generateRecommendation 生成操作推荐
func (d *DogeUSDTForecastService) generateRecommendation(scorePercent float64) string {
	switch {
	case scorePercent >= 80:
		return "强烈看涨 - 建议关注买入机会"
	case scorePercent >= 60:
		return "看涨 - 可考虑适量买入"
	case scorePercent >= 40:
		return "中性偏多 - 观望为主"
	case scorePercent >= 20:
		return "中性偏空 - 谨慎操作"
	default:
		return "看空 - 建议回避"
	}
}

// UpdateData 更新数据（手动更新，建议使用实时监控）
func (d *DogeUSDTForecastService) UpdateData() error {
	// 获取最新的K线数据，保持与初始化一致的数据量
	klines, err := d.client.NewKlinesService().
		Symbol(d.symbol).
		Interval("1d").
		Limit(200). // 与InitializeData保持一致
		Do(context.Background())

	if err != nil {
		return fmt.Errorf("更新K线数据失败: %v", err)
	}

	// 验证数据量是否足够
	if len(klines) < 50 {
		return fmt.Errorf("更新的K线数据不足，仅获取到%d根，需要至少50根", len(klines))
	}

	d.dataMutex.Lock()
	d.klineData = klines
	d.calculateVolumeAverage()
	d.lastUpdate = time.Now()
	d.dataMutex.Unlock()

	log.Printf("DOGE/USDT预测服务数据更新完成，当前有%d根K线数据", len(klines))
	return nil
}

// GetLastUpdateTime 获取最后更新时间
func (d *DogeUSDTForecastService) GetLastUpdateTime() time.Time {
	return d.lastUpdate
}

// GetSymbol 获取交易对符号
func (d *DogeUSDTForecastService) GetSymbol() string {
	return d.symbol
}

// IsDataReady 检查数据是否准备就绪（线程安全）
func (d *DogeUSDTForecastService) IsDataReady() bool {
	d.dataMutex.RLock()
	defer d.dataMutex.RUnlock()
	return d.isDataReady()
}

// isDataReady 内部方法，检查数据是否准备就绪（非线程安全）
func (d *DogeUSDTForecastService) isDataReady() bool {
	return len(d.klineData) >= 50
}

/*
使用示例：

```go
// 创建服务
client := binance.NewClient(apiKey, secretKey)
service := NewDogeUSDTForecastService(client)

// 初始化历史数据
if err := service.InitializeData(); err != nil {
	log.Fatal(err)
}

// 设置回调函数
service.SetPriceUpdateCallback(func(price float64) {
	log.Printf("价格更新: %.6f", price)
})

service.SetScoreUpdateCallback(func(score *ForecastScore) {
	log.Printf("评分更新: %.2f%% - %s", score.ScorePercent, score.Recommendation)
})

service.SetKlineUpdateCallback(func(kline *binance.Kline) {
	log.Printf("K线更新: %s", kline.Close)
})

// 启动实时监控
if err := service.StartRealTimeMonitoring(); err != nil {
	log.Fatal(err)
}

// 程序运行期间...
// 可以随时获取当前数据
currentPrice := service.GetCurrentPrice()
currentScore, _ := service.CalculateScore()

// 停止监控
defer service.StopRealTimeMonitoring()
```

主要改进：
1. 基于WebSocket的实时数据流
2. 事件驱动的评分计算
3. 并发安全的数据访问
4. 可配置的回调函数
5. 自动数据更新和管理
6. 更高的数据实时性和准确性
*/

// calculateVolumeAboveAverage 计算成交量 > 1.5倍均值
func (d *DogeUSDTForecastService) calculateVolumeAboveAverage() float64 {
	if len(d.klineData) == 0 {
		return 0
	}

	lastKline := d.klineData[len(d.klineData)-1]
	currentVolume, _ := strconv.ParseFloat(lastKline.Volume, 64)

	if currentVolume > d.volumeAvg*1.5 {
		return 1.0
	}
	return 0
}

// calculatePriceAbove20MA 计算当前价格 > 20MA
func (d *DogeUSDTForecastService) calculatePriceAbove20MA(currentPrice float64) float64 {
	ma20 := d.calculateMA(20)
	if currentPrice > ma20 {
		return 1.0
	}
	return 0
}

// calculateConsecutiveBullCandles 计算连续3根阳线
func (d *DogeUSDTForecastService) calculateConsecutiveBullCandles() float64 {
	if len(d.klineData) < 3 {
		return 0
	}

	// 检查最近3根K线是否都是阳线
	for i := len(d.klineData) - 3; i < len(d.klineData); i++ {
		open, _ := strconv.ParseFloat(d.klineData[i].Open, 64)
		close, _ := strconv.ParseFloat(d.klineData[i].Close, 64)
		if close <= open {
			return 0
		}
	}
	return 1.0
}

// calculateBollingerBreakout 计算突破布林带上轨
func (d *DogeUSDTForecastService) calculateBollingerBreakout(currentPrice float64) float64 {
	upperBand := d.calculateBollingerUpperBand(20, 2.0)
	if currentPrice > upperBand {
		return 1.0
	}
	return 0
}

// calculateConsecutiveAboveBollinger 计算连续2日收盘价 > 上轨
func (d *DogeUSDTForecastService) calculateConsecutiveAboveBollinger() float64 {
	if len(d.klineData) < 22 { // 需要20+2天数据
		return 0
	}

	// 计算前两天的布林带上轨和收盘价
	for i := 0; i < 2; i++ {
		subData := d.klineData[:len(d.klineData)-1+i]
		upperBand := d.calculateBollingerUpperBandFromData(subData, 20, 2.0)
		close, _ := strconv.ParseFloat(d.klineData[len(d.klineData)-2+i].Close, 64)
		if close <= upperBand {
			return 0
		}
	}
	return 1.0
}